<script>
	/*
  关于ajax请求的状态码：
- 2XX: 表示成功处理请求, 如200, 201
- 3XX: 需要重定向, 浏览器直接跳转,
     如302(地址重定向,使用户跳转到另外一个地址),
       304(使用缓存,相当于将本次请求重定向到用户浏览器内存中)
- 4XX: 客户端请求错误,
  如:  403(禁止访问,服务器有该资源,但是你的权限不够),
       404(服务器没有该资源,服务器会将接口当作资源来看待)
- 5XX: 服务器端错误, 如: 500

  */

	/*
 #### 区别ajax请求与一般HTTP请求
注意:
​	**ajax不是一种全新的网络请求,它只是一种发送网络请求的技术**
​	**ajax是用来发送http请求的一门技术,只存在于浏览器端**

- 对服务器端来说, 没有任何区别, 区别在浏览器端
- 浏览器端发请求: 只有XHR或fetch发出
  Fetch 是一个现代的概念, 等同于 XMLHttpRequest。
    它提供了许多与XMLHttpRequest相同的功能，
    但被设计成更具可扩展性和高效性。
    fetch 不会发送跨域 cookies，除非你使用了 credentials 的初始化选项。
    https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Basic_concepts
    使用fetch:https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch

      fetch('http://example.com/movies.json')
    .then(response => response.json())
    .then(data => console.log(data));
- 浏览器端接收到响应
  - 一般请求: 浏览器一般会直接显示响应体数据, 也就是我们常说的刷新/跳转页面
  - ajax请求: 浏览器不会对界面进行任何更新操作, 只是调用监视的回调函数并传入响应相关数据
 */
</script>
<script>
	// 封装一个简易的ajax异步请求函数
	/* 
xhr + promise 封装一个异步ajax请求的通用函数  简洁版
*/
	function ajax(url) {
		return new Promise((resolve, reject) => {
			// 1.创建一个XHR对象
			const xhr = new XMLHttpRequest();
			// 2.初始化一个异步请求(还没发请求)
			xhr.open("POST", url, true);
			//4.监视请求是否响应成功
			xhr.onreadystatechange = function () {
				/*
        ajax引擎得到响应数据后
        	将xhr的readyState属性指定为4
        	将响应数据保存在response / responseText属性上
        	调用此回调函数
        */

				// 如果状态值不为4, 直接结束(请求还没有结束)
				if (xhr.readyState !== 4) {
					return;
				}
				// 如果响应码在200~~299之间, 说明请求都是成功的
				if (xhr.status >= 200 && xhr.status < 300) {
					// 指定promise成功及结果值
					resolve(JSON.parse(xhr.responseText));
				} else {
					// 请求失败了
					// 指定promise失败及结果值
					reject(new Error("request error staus " + request.status));
				}
			};
			//3.发送请求,并携带请求体参数
			xhr.send({ a: 1 });
		});
	}
</script>
<script>
	/* 
xhr + promise 封装一个异步ajax请求的通用函数  加强版
  返回值: promise
  参数为配置对象
    url: 请求地址
    params: 包含所有query请求参数的对象
    data: 包含所有请求体参数数据的对象
    method: 为请求方式
*/
	function axios({ url, params = {}, data = {}, method = "GET" }) {
		// 1.返回一个promise对象
		return new Promise((resolve, reject) => {
			// 2.创建一个XHR对象
			const request = new XMLHttpRequest();

			// 根据params拼接que ry参数
			let queryStr = Object.keys(params).reduce((pre, key) => {
				pre += `&${key}=${params[key]}`;
				return pre;
			}, "");

			if (queryStr.length > 0) {
				queryStr = queryStr.substring(1);
				url += "?" + queryStr;
			}
			// 请求方式转换为大写
			method = method.toUpperCase();

			// 初始化一个异步请求(还没发请求)
			request.open(method, url, true);
			// 绑定请求状态改变的监听
			request.onreadystatechange = function () {
				// 如果状态值不为4, 直接结束(请求还没有结束)
				if (request.readyState !== 4) {
					return;
				}
				// 如果响应码在200~~299之间, 说明请求都是成功的
				if (request.status >= 200 && request.status < 300) {
					// 准备响应数据对象
					const responseData = {
						data: JSON.parse(request.response),
						status: request.status,
						statusText: request.statusText,
					};
					// 指定promise成功及结果值
					resolve(responseData);
				} else {
					// 请求失败了
					// 指定promise失败及结果值
					const error = new Error("request error staus " + request.status);
					reject(error);
				}
			};

			// 如果是post/put请求
			if (method === "POST" || method === "PUT" || method === "DELETE") {
				// 设置请求头: 使请求体参数以json形式传递
				//!!!!!!!!!!!!!工作中一定要注意
				request.setRequestHeader(
					"Content-Type",
					"application/json;charset=utf-8"
				);
				// 包含所有请求参数的对象转换为json格式
				const dataJson = JSON.stringify(data);
				// 发送请求, 指定请求体数据
				request.send(dataJson);
			} else {
				// GET请求
				// 发送请求
				request.send(null);
			}
		});
	}
</script>
